﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Castle.Components.Common.TemplateEngine;
using CsvSerializer;
using CsvSerializer.CsvWriter;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using ProtoBuf;
using Formatting = Newtonsoft.Json.Formatting;

namespace mst_regex
{
    [ProtoContract, JsonObject(MemberSerialization.OptIn)]
    public class OddlotStockPosition : IStockPosition, IPersistable
    {
        [JsonProperty(PropertyName = "Value"), XmlElement(ElementName = "Value"), ProtoMember(10)]
        public decimal ValueInMillions { get; set; }

        [JsonProperty, ProtoMember(20)]
        public int Quantity { get; set; }

        [JsonProperty, ProtoMember(30)]
        public int Trades { get; set; }

        [JsonProperty, ProtoMember(40)]
        public decimal MinPrice { get; set; }

        [JsonProperty, ProtoMember(50)]
        public decimal MaxPrice { get; set; }

        #region IPersistable Members

        public override string ToString()
        {
            return
                string.Format(
                    "symbol={0},exchange={1},date={2},maxprice={3},minprice={4},value={5},trades={6},quantity={7}",
                    Symbol,
                    StockExchange,
                    EffectiveDate.ToString("yyyy-MM-dd"),
                    MaxPrice, MinPrice, ValueInMillions, Trades, Quantity);
        }

        public string ToCsv()
        {
            using (var memoryStream = new MemoryStream())
            using (var streamWriter = new StreamWriter(memoryStream))
            using (var streamReader = new StreamReader(memoryStream))
            {
                var options = new CsvWriterOptions
                {
                    Delimiter = GlobalOptions.Instance.CsvDelimiterChar,
                    HasHeaderRecord = GlobalOptions.Instance.CsvHasHeader,
                    Quote = GlobalOptions.Instance.CsvQuoteChar
                };
                using (var writer = new CsvWriter(streamWriter, options))
                {
                    writer.WriteRecord(this);
                    memoryStream.Position = 0;
                    return streamReader.ReadToEnd();
                }
            }
            
            return string.Format("{0},{1},{2},{3},{4},{5},{6}",
                                 Symbol,
                                 EffectiveDate.ToString("yyyy-MM-dd"),
                                 MaxPrice, MinPrice, ValueInMillions, Trades, Quantity);
        }

        public string ToXml()
        {
            string xmlString = null;
            try
            {
                using (var stream = new MemoryStream())
                {
                    var settings = new XmlWriterSettings
                                       {
                                           Indent = true,
                                           OmitXmlDeclaration = true,
                                           Encoding = Encoding.UTF8,
                                           ConformanceLevel = ConformanceLevel.Auto
                                       };

                    using (var writer = XmlWriter.Create(stream, settings))
                    {
                        var serializer = new XmlSerializer(typeof (OddlotStockPosition));
                        serializer.Serialize(writer, this);
                        writer.Flush();
                    }
                    xmlString = Encoding.Default.GetString(stream.ToArray());
                }
            }
            catch
            {
            }

            return xmlString;
        }

        public string ToJson()
        {
            return JsonConvert.SerializeObject(this, Formatting.Indented);
        }

        public byte[] ToProtobuf()
        {
            byte[] proto;
            using (var stream = new MemoryStream())
            {
                Serializer.Serialize(stream, this);
                proto = stream.ToArray();
            }

            return proto;
        }

        IPersistable IPersistable.FromXml(string xml)
        {
            return FromXml(xml);
        }

        public static OddlotStockPosition FromXml(string xml)
        {
            OddlotStockPosition obj = null;
            using (var stringReader = new StringReader(xml))
            {
                using (var xmlReader = new XmlTextReader(stringReader))
                {
                    var serializer = new XmlSerializer(typeof(OddlotStockPosition));
                    obj = (OddlotStockPosition)serializer.Deserialize(xmlReader);
                }
            }
            return obj;
        }

        IPersistable IPersistable.FromJson(string json)
        {
            return FromJson(json);
        }

        IPersistable IPersistable.FromProtobuf(byte[] proto)
        {
            return FromProtobuf(proto);
        }

        public static OddlotStockPosition FromProtobuf(byte[] proto)
        {
            using (var stream = new MemoryStream())
            {
                stream.Write(proto, 0, proto.Length);
                stream.Seek(0, SeekOrigin.Begin);

                return Serializer.Deserialize<OddlotStockPosition>(stream);
            }
        }

        public static OddlotStockPosition FromJson(string json)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IStockPosition Members

        [JsonProperty, ProtoMember(60)]
        public StockExchangeType StockExchange { get; set; }

        [JsonProperty, JsonConverter(typeof(JavaScriptDateTimeConverter)), XmlElement(DataType = "date"), ProtoMember(70)]
        public DateTime EffectiveDate { get; set; }

        [JsonProperty, ProtoMember(80)]
        public string Symbol { get; set; }

        public IPersistable FromCsv(string csv, bool containsHeader)
        {
            throw new NotImplementedException();
        }

        public string ProcessTemplate(ITemplateEngine engine, string templateFile)
        {
            var context = new Hashtable
                              {
                                  {"mn", MinPrice},
                                  {"max", MaxPrice},
                                  {"quantity", Quantity},
                                  {"value", ValueInMillions},
                                  {"trades", Trades},
                                  {"exchange", StockExchange},
                                  {"date", EffectiveDate.ToString("yyyy-MM-dd")},
                                  {"symbol", Symbol}
                              };

            using (var writer = new StringWriter())
            {
                engine.Process(context, templateFile, writer);
                return writer.ToString();
            }
        }

        #endregion
    }
}